package cn.duhengkui.national.valuelist.gen;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.duhengkui.national.valuelist.tool.Column;
import cn.duhengkui.national.valuelist.tool.EntityData;


/**   
 * <table border="1">
 *	<tr><td>包名称：</td><td>cn.duhengkui.national.valuelist.gen</td></tr>
 *	<tr><td>类名称：</td><td>DataBaseInfo</td></tr>
 *	<tr><td>类描述：</td><td>数据库连接信息</td></tr>
 *	<tr><td>创建人：</td><td>杜恒奎</td></tr>
 *  <tr><td>创建时间：</td><td>2018年6月8日/上午10:44:23</td></tr> 
 *  <tr><td>版本：</td><td>1.0.0</td></tr>
 * </table>   
 *     
 */
public class DataBaseInfo {
	/**
	 * Logger for this class
	 */
	private String driver;
	
	private String url;
	
	private String userName;
	
	private String password;
	
	public EntityFactory getEntityFactory(){
		EntityFactory factory = null;
		if(driver.indexOf("mysql") >= 0){
			factory = new cn.duhengkui.national.valuelist.gen.mysql.EntityFactoryImpl();
		}else if(driver.indexOf("postgresql") >= 0){
			factory = new cn.duhengkui.national.valuelist.gen.postgresql.EntityFactoryImpl();
		}else if(driver.indexOf("oracle") >= 0){
			factory = new cn.duhengkui.national.valuelist.gen.oracle.EntityFactoryImpl();
		}
		return factory;
	}
	
	public DataBaseInfo(String driver, String url, String userName, String password) {
		this.driver = driver;
		this.url = url;
		this.userName = userName;
		this.password = password;
	}
	
	
	List<EntityData> entityList(boolean isUpperEntityName, String... entityNames) {
		Connection con = getConnection();
		ResultSet rs = null;
		List<EntityData> list = new ArrayList<>();
		try {
			DatabaseMetaData metaData = con.getMetaData();
			rs = metaData.getTables(null, "%", "%", new String[] {"TABLE", "VIEW"});
			Map<String, String> map = new HashMap<>();
			while(rs.next()) {
				map.put(rs.getString("TABLE_NAME").toUpperCase(), rs.getString("TABLE_TYPE"));
			}
			if(entityNames == null || entityNames.length == 0) {
				for(String entityName : map.keySet()) {
					list.add(readEntity(metaData, entityName, map.get(entityName), isUpperEntityName));
				}
			} else {
				for(String entityName : entityNames) {
					if (map.containsKey(entityName.toUpperCase())) {
						list.add(readEntity(metaData, entityName.toUpperCase(), map.get(entityName.toUpperCase()), isUpperEntityName));
					}
				}
			}
		} catch (SQLException e) {
			throw new RuntimeException(e);
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					throw new RuntimeException(e);
				}
			}
			closeConnection(con);
		}
		return list;
	}
	
	private EntityData readEntity(final DatabaseMetaData metaData, String entityName, String entityType, boolean isUpperEntityName) {
		ResultSet rs = null;
		try {
			if (!isUpperEntityName) {
				entityName = entityName.toLowerCase();
			}
			rs = metaData.getPrimaryKeys(null, null, entityName);
			
		
			List<String> pks = new ArrayList<>(1);
			while(rs.next()) {
				pks.add(rs.getString("COLUMN_NAME"));
			}
			rs.close();
			rs = metaData.getColumns(null, "%", entityName, "%");
/*			ResultSetMetaData rsmd = rs.getMetaData();
			int count = rsmd.getColumnCount();
			for (int i = 0; i < count; i++) {
				System.out.println(rsmd.getColumnName(i + 1));
			}*/
			EntityData entity = new EntityData();
			entity.setName(entityName);
			entity.setType(entityType);
			while(rs.next()) {
				Column column = new Column();
				column.setTypeName(rs.getString("TYPE_NAME"));
				column.setPK(!pks.isEmpty() && pks.contains(rs.getString("COLUMN_NAME")));
				if(driver.indexOf("oracle") >= 0){
					column.setAutoincrement(false);
				}else{
					column.setAutoincrement(new Boolean(rs.getString("IS_AUTOINCREMENT")));
				}
				column.setName(rs.getString("COLUMN_NAME"));
				column.setType(rs.getInt("DATA_TYPE"));
				column.setLength(rs.getInt("COLUMN_SIZE"));
				column.setPrecision(rs.getInt("COLUMN_SIZE"));
				column.setScale(rs.getInt("DECIMAL_DIGITS"));
				column.setNotNull(rs.getInt("NULLABLE") == 0);
				column.setDefaultValue(rs.getString("COLUMN_DEF") == null ? "" 
						: rs.getString("COLUMN_DEF").replace("'", ""));
				entity.addColumn(column);
				if(column.isPK()) {
					entity.addPK(rs.getString("COLUMN_NAME"), column);
				}
			}
			return entity;
		} catch (SQLException e) {
			throw new RuntimeException(e);
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					throw new RuntimeException(e);
				}
			}
		}
	}
	
	private Connection getConnection() {
		Connection con = null;
		try {
			Class.forName(driver);
			con = DriverManager.getConnection(url, userName, password);
		} catch (ClassNotFoundException | SQLException e) {
			throw new RuntimeException(e);
		}
		return con;
	}
	
	private void closeConnection(final Connection con) {
		try {
			if (con != null) {
				con.close();
			}
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
}